#ifndef __I_SINGLETON_H__
#define __I_SINGLETON_H__

/*
 * Usage:
 * class MySingleton : public SinglePattern {
 * 	  DECLARE_SINGLETON(MySingleton);
 * 
 *  protected:
 * 	  virtual void InitializeInstance() { }
 * 	  virtual void DisposeInstance() { }
 * 
 *  public:
 * 	  void Run() { }
 *  };
 * 
 *  MySingleton::GetInstance()->Run();
 */

#include <Windows.h>
#include <memory>

// Base Singleton class, thread safe
class ISingleton {
protected: 
	virtual void				InitialInstance() = 0; 
	virtual void				DisposeInstance() = 0; 
};

// Thread safe class
class CResGuard {
public:
	class CGuard {
	public:
								CGuard(CResGuard& rg) : m_rg(rg) { m_rg.Guard(); }
								~CGuard() { m_rg.UnGuard(); }

	protected:
		CResGuard&				m_rg;
	};

private:
	CRITICAL_SECTION			m_cs;
	long						m_lGrdCnt;

	void						Guard() { EnterCriticalSection(&m_cs); m_lGrdCnt++; }
	void						UnGuard() { m_lGrdCnt--; LeaveCriticalSection(&m_cs); }

	friend class CResGuard::CGuard;

public:
								CResGuard() { m_lGrdCnt = 0; InitializeCriticalSection(&m_cs); }
								~CResGuard() { DeleteCriticalSection(&m_cs); }

	bool						IsGuarded() const { return (m_lGrdCnt > 0); }
};

// Singleton Container
template<class T>
class Singleton {
	friend class std::auto_ptr<T>;

protected:
	static std::auto_ptr<T>	m_Instance;
	static CResGuard			m_rs;

protected:
								Singleton() { }
	virtual						~Singleton() { }

public:
	static T*					GetInstance()
	{
		CResGuard::CGuard		gd(m_rs);
		if (m_Instance.get() == NULL) {
			m_Instance.reset(new T());
		}
		return m_Instance.get();
	}
};

template<class T>
CResGuard Singleton<T>::m_rs;

template<class T>
std::auto_ptr<T> Singleton<T>::m_Instance;

// MACRO of ISingleton to use
#define DECLARE_SINGLETON(type)										\
	friend class std::auto_ptr<type>;								\
	friend class Singleton<type>;									\
																	\
public:																\
	static type					*GetInstance()						\
	{																\
		return Singleton<type>::GetInstance();						\
	}																\
																	\
protected:															\
								type()								\
	{																\
		InitialInstance();											\
	}																\
																	\
public:																\
	virtual						~type()								\
	{																\
		DisposeInstance();											\
	}			

// test ISingleton
class SingletonTest : public ISingleton {
	DECLARE_SINGLETON(SingletonTest);

protected:
	virtual void				InitialInstance() { }
	virtual void				DisposeInstance() { }

public:
	void						Run() { printf("Singleton Succeed!\n"); }
};


#endif ///> end of __I_SINGLETON_H__